#include "list.h"

#include <assert.h>

void List_Init(List * l)
{
	l->first = NULL;
	l->last = NULL;
	l->count = 0;
}

void List_Copy(const List * source,List** destination)
{
	Cell* c;
	if (!List_IsEmpty(source))
	{
		c = source->first;
		List_Init(*destination);
		while(c != NULL)
		{
			List_InsertLast(*destination,c->value);
			c = c->next;
		}
	}
}

int List_IsEmpty(const List * l)
{
	return (l->first == NULL);
}

Cell* List_InsertAt(List* l, Element e, int position)
{
	unsigned int i; Cell* c;
	if (position < l->count)
	{
		c = l->first;
		for(i = 0; i < position; i++)
			c = c->next;
		i = (unsigned int) c;
		c = (Cell*) malloc(sizeof(Cell));
		c->next = ((Cell*)i)->next;
		((Cell*)i)->next = c;
		l->count++;
		return c;
	}
	else
		return NULL;
}

Cell* List_Insert(List* l, Element e, Element at)
{
	Cell* c = (Cell*) malloc(sizeof(Cell));
	c->value._p = List_Search(l,at);
	if(((Cell*)c->value._p) == NULL)
	{
		free(c);
		return NULL;
	}
	c->next = ((Cell*)c->value._p)->next;
	((Cell*)c->value._p)->next = c;
	c->value = e;
	l->count ++;
	return c;
}

void List_Remove(List* l, Element e)
{
	Cell* c;
	if(l->count > 0)
	{
		c = l->first;
		if(c->value._p == e._p)
		{
			if (l->count > 1)
			{
				l->first = c->next;
				l->count--;
				free(c);
			}
			else
			{
				l->first = NULL;
				l->last = NULL;
				l->count = 0;
				free(c);
			}
		}
		else
		{
			c = c->next;
			while (c->next != NULL)
			{
				if (c->next->value._p == e._p)
				{
					if(c->next == l->last)
					{
						c->next = NULL;
						l->last = c;
					}
					else
					{
						c->next = c->next->next;
					}
					free(c->next);
					l->count--;
					break;
				}
				c = c->next;
			}
		}
	}
}

void List_InsertLast(List* l,Element e)
{
	Cell* c = (Cell*) malloc(sizeof(Cell));
	c->value = e;
	if(l->count == 0)
	{
		c->next = NULL;
		l->first = c;
		l->last = c;
	}
	else
	{
		c->next = NULL;
		l->last->next = c;
		l->last = c;
	}
	l->count++;
}

void List_InsertFirst(List* l,Element  e)
{
	Cell* c = (Cell*) malloc(sizeof(Cell));
	c->value = e;
	if(l->count == 0)
	{
		c->next = NULL;
		l->first = c;
		l->last = c;
	}
	else
	{
		c->next = l->first;
		l->first = c;
	}
	l->count++;
}

Element List_GetFirst(const List* l)
{
	return l->first->value;
}

Element List_GetLast(const List* l)
{
	return l->last->value;
}

Element List_ReadFirst(List* l)
{
	Cell* c = l->first; Element e;
	e._p = NULL;
	if (l->count == 0)
		return e;
	e = l->first->value;
	if (l->count == 1)
	{
		l->first = NULL;
		l->last = NULL;
	}
	else
	{
		l->first = l->first->next;
	}
	free(c);
	l->count--;
	return e;
}

Element List_ReadLast(List* l)
{
	Cell* c = l->last; Element e;
	e._p = NULL;
	if (l->count == 0)
		return e;
	e = l->first->value;
	if (l->count == 1)
	{
		l->first = NULL;
		l->last = NULL;
	}
	else
	{
		l->last->next = NULL;
	}
	free(c);
	l->count--;
	return e;
}

Cell* List_Search(const List* l,Element e)
{
	Cell* c = l->first;
	while(c->next!=NULL)
	{
		if(c->value._p == e._p)
			return c;
		c=c->next;
	}
	return NULL;
}

void List_ToArray(Element** element, const List* l)
{
	int i;
	Cell* c = l->first;
	Element* array;
	*element = (Element*) malloc(sizeof(Element) * l->count);
	for( i = 0; i < l->count; i++)
	{
		array = *element;
		array[i] = c->value;  
		c = c->next;
	}
}

void List_Destroy(List* l)
{
	while (l->first != NULL)
	{
		l->last = l->first;
		l->first = l->first->next;
		free(l->last);
	}
	l->first = NULL;
	l->last = NULL;
	l->count = 0;
}